﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Noris.Tools.QCode.QrEncoder
{
    #region SupportClass
    /// <summary>
    /// Contains conversion support elements such as classes, interfaces and static methods.
    /// </summary>
    internal class SupportClass
    {
        /// <summary>
        /// Converts an array of sbytes to an array of bytes
        /// </summary>
        /// <param name="sbyteArray">The array of sbytes to be converted</param>
        /// <returns>The new array of bytes</returns>
        internal static byte[] ToByteArray(sbyte[] sbyteArray)
        {
            byte[] byteArray = null;

            if (sbyteArray != null)
            {
                byteArray = new byte[sbyteArray.Length];
                for (int index = 0; index < sbyteArray.Length; index++)
                    byteArray[index] = (byte)sbyteArray[index];
            }
            return byteArray;
        }

        /// <summary>
        /// Converts a string to an array of bytes
        /// </summary>
        /// <param name="sourceString">The string to be converted</param>
        /// <returns>The new array of bytes</returns>
        internal static byte[] ToByteArray(System.String sourceString)
        {
            return System.Text.UTF8Encoding.UTF8.GetBytes(sourceString);
        }

        /// <summary>
        /// Converts a array of object-type instances to a byte-type array.
        /// </summary>
        /// <param name="tempObjectArray">Array to convert.</param>
        /// <returns>An array of byte type elements.</returns>
        internal static byte[] ToByteArray(System.Object[] tempObjectArray)
        {
            byte[] byteArray = null;
            if (tempObjectArray != null)
            {
                byteArray = new byte[tempObjectArray.Length];
                for (int index = 0; index < tempObjectArray.Length; index++)
                    byteArray[index] = (byte)tempObjectArray[index];
            }
            return byteArray;
        }

        /*******************************/
        /// <summary>
        /// Performs an unsigned bitwise right shift with the specified number
        /// </summary>
        /// <param name="number">Number to operate on</param>
        /// <param name="bits">Ammount of bits to shift</param>
        /// <returns>The resulting number from the shift operation</returns>
        internal static int URShift(int number, int bits)
        {
            if (number >= 0)
                return number >> bits;
            else
                return (number >> bits) + (2 << ~bits);
        }

        /// <summary>
        /// Performs an unsigned bitwise right shift with the specified number
        /// </summary>
        /// <param name="number">Number to operate on</param>
        /// <param name="bits">Ammount of bits to shift</param>
        /// <returns>The resulting number from the shift operation</returns>
        internal static int URShift(int number, long bits)
        {
            return URShift(number, (int)bits);
        }

        /// <summary>
        /// Performs an unsigned bitwise right shift with the specified number
        /// </summary>
        /// <param name="number">Number to operate on</param>
        /// <param name="bits">Ammount of bits to shift</param>
        /// <returns>The resulting number from the shift operation</returns>
        internal static long URShift(long number, int bits)
        {
            if (number >= 0)
                return number >> bits;
            else
                return (number >> bits) + (2L << ~bits);
        }

        /// <summary>
        /// Performs an unsigned bitwise right shift with the specified number
        /// </summary>
        /// <param name="number">Number to operate on</param>
        /// <param name="bits">Ammount of bits to shift</param>
        /// <returns>The resulting number from the shift operation</returns>
        internal static long URShift(long number, long bits)
        {
            return URShift(number, (int)bits);
        }

        /*******************************/
        /// <summary>
        /// This method returns the literal value received
        /// </summary>
        /// <param name="literal">The literal to return</param>
        /// <returns>The received value</returns>
        internal static long Identity(long literal)
        {
            return literal;
        }

        /// <summary>
        /// This method returns the literal value received
        /// </summary>
        /// <param name="literal">The literal to return</param>
        /// <returns>The received value</returns>
        internal static ulong Identity(ulong literal)
        {
            return literal;
        }

        /// <summary>
        /// This method returns the literal value received
        /// </summary>
        /// <param name="literal">The literal to return</param>
        /// <returns>The received value</returns>
        internal static float Identity(float literal)
        {
            return literal;
        }

        /// <summary>
        /// This method returns the literal value received
        /// </summary>
        /// <param name="literal">The literal to return</param>
        /// <returns>The received value</returns>
        internal static double Identity(double literal)
        {
            return literal;
        }

        /*******************************/
        /// <summary>
        /// Copies an array of chars obtained from a String into a specified array of chars
        /// </summary>
        /// <param name="sourceString">The String to get the chars from</param>
        /// <param name="sourceStart">Position of the String to start getting the chars</param>
        /// <param name="sourceEnd">Position of the String to end getting the chars</param>
        /// <param name="destinationArray">Array to return the chars</param>
        /// <param name="destinationStart">Position of the destination array of chars to start storing the chars</param>
        /// <returns>An array of chars</returns>
        internal static void GetCharsFromString(System.String sourceString, int sourceStart, int sourceEnd, char[] destinationArray, int destinationStart)
        {
            int sourceCounter;
            int destinationCounter;
            sourceCounter = sourceStart;
            destinationCounter = destinationStart;
            while (sourceCounter < sourceEnd)
            {
                destinationArray[destinationCounter] = (char)sourceString[sourceCounter];
                sourceCounter++;
                destinationCounter++;
            }
        }

        /*******************************/
        /// <summary>
        /// Sets the capacity for the specified ArrayList
        /// </summary>
        /// <param name="vector">The ArrayList which capacity will be set</param>
        /// <param name="newCapacity">The new capacity value</param>
        internal static void SetCapacity(System.Collections.ArrayList vector, int newCapacity)
        {
            if (newCapacity > vector.Count)
                vector.AddRange(new Array[newCapacity - vector.Count]);
            else if (newCapacity < vector.Count)
                vector.RemoveRange(newCapacity, vector.Count - newCapacity);
            vector.Capacity = newCapacity;
        }



        /*******************************/
        /// <summary>
        /// Receives a byte array and returns it transformed in an sbyte array
        /// </summary>
        /// <param name="byteArray">Byte array to process</param>
        /// <returns>The transformed array</returns>
        internal static sbyte[] ToSByteArray(byte[] byteArray)
        {
            sbyte[] sbyteArray = null;
            if (byteArray != null)
            {
                sbyteArray = new sbyte[byteArray.Length];
                for (int index = 0; index < byteArray.Length; index++)
                    sbyteArray[index] = (sbyte)byteArray[index];
            }
            return sbyteArray;
        }

    }
    #endregion
    #region ECI
    /// <summary> Superclass of classes encapsulating types ECIs, according to "Extended Channel Interpretations"
    /// 5.3 of ISO 18004.
    /// 
    /// </summary>
    /// <author>  Sean Owen
    /// </author>
    /// <author>www.Redivivus.in (suraj.supekar@redivivus.in) - Ported from ZXING Java Source 
    /// </author>
    internal abstract class ECI
    {
        virtual internal int Value
        {
            get
            {
                return value_Renamed;
            }

        }

        //UPGRADE_NOTE: Final was removed from the declaration of 'value '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'"
        private int value_Renamed;

        internal ECI(int value_Renamed)
        {
            this.value_Renamed = value_Renamed;
        }

        /// <param name="value">ECI value
        /// </param>
        /// <returns> {@link ECI} representing ECI of given value, or null if it is legal but unsupported
        /// </returns>
        /// <throws>  IllegalArgumentException if ECI value is invalid </throws>
        internal static ECI getECIByValue(int value_Renamed)
        {
            if (value_Renamed < 0 || value_Renamed > 999999)
            {
                throw new System.ArgumentException("Bad ECI value: " + value_Renamed);
            }
            if (value_Renamed < 900)
            {
                // Character set ECIs use 000000 - 000899
                return CharacterSetECI.getCharacterSetECIByValue(value_Renamed);
            }
            return null;
        }
    }
    #endregion
    #region CharacterSetECI
    /// <summary> Encapsulates a Character Set ECI, according to "Extended Channel Interpretations" 5.3.1.1
    /// of ISO 18004.
    /// 
    /// </summary>
    /// <author>  Sean Owen
    /// </author>
    /// <author>www.Redivivus.in (suraj.supekar@redivivus.in) - Ported from ZXING Java Source 
    /// </author>
    internal sealed class CharacterSetECI : ECI
    {
        internal System.String EncodingName
        {
            get
            {
                return encodingName;
            }

        }

        private static System.Collections.Hashtable VALUE_TO_ECI;
        private static System.Collections.Hashtable NAME_TO_ECI;

        private static void initialize()
        {
            VALUE_TO_ECI = System.Collections.Hashtable.Synchronized(new System.Collections.Hashtable(29));
            NAME_TO_ECI = System.Collections.Hashtable.Synchronized(new System.Collections.Hashtable(29));
            // TODO figure out if these values are even right!
            addCharacterSet(0, "Cp437");
            addCharacterSet(1, new System.String[] { "ISO8859_1", "ISO-8859-1" });
            addCharacterSet(2, "Cp437");
            addCharacterSet(3, new System.String[] { "ISO8859_1", "ISO-8859-1" });
            addCharacterSet(4, "ISO8859_2");
            addCharacterSet(5, "ISO8859_3");
            addCharacterSet(6, "ISO8859_4");
            addCharacterSet(7, "ISO8859_5");
            addCharacterSet(8, "ISO8859_6");
            addCharacterSet(9, "ISO8859_7");
            addCharacterSet(10, "ISO8859_8");
            addCharacterSet(11, "ISO8859_9");
            addCharacterSet(12, "ISO8859_10");
            addCharacterSet(13, "ISO8859_11");
            addCharacterSet(15, "ISO8859_13");
            addCharacterSet(16, "ISO8859_14");
            addCharacterSet(17, "ISO8859_15");
            addCharacterSet(18, "ISO8859_16");
            addCharacterSet(20, new System.String[] { "SJIS", "Shift_JIS" });
        }

        //UPGRADE_NOTE: Final was removed from the declaration of 'encodingName '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'"
        private System.String encodingName;

        private CharacterSetECI(int value_Renamed, System.String encodingName)
            : base(value_Renamed)
        {
            this.encodingName = encodingName;
        }

        private static void addCharacterSet(int value_Renamed, System.String encodingName)
        {
            CharacterSetECI eci = new CharacterSetECI(value_Renamed, encodingName);
            VALUE_TO_ECI[(System.Int32)value_Renamed] = eci; // can't use valueOf
            NAME_TO_ECI[encodingName] = eci;
        }

        private static void addCharacterSet(int value_Renamed, System.String[] encodingNames)
        {
            CharacterSetECI eci = new CharacterSetECI(value_Renamed, encodingNames[0]);
            VALUE_TO_ECI[(System.Int32)value_Renamed] = eci; // can't use valueOf
            for (int i = 0; i < encodingNames.Length; i++)
            {
                NAME_TO_ECI[encodingNames[i]] = eci;
            }
        }

        /// <param name="value">character set ECI value
        /// </param>
        /// <returns> {@link CharacterSetECI} representing ECI of given value, or null if it is legal but
        /// unsupported
        /// </returns>
        /// <throws>  IllegalArgumentException if ECI value is invalid </throws>
        internal static CharacterSetECI getCharacterSetECIByValue(int value_Renamed)
        {
            if (VALUE_TO_ECI == null)
            {
                initialize();
            }
            if (value_Renamed < 0 || value_Renamed >= 900)
            {
                throw new System.ArgumentException("Bad ECI value: " + value_Renamed);
            }
            return (CharacterSetECI)VALUE_TO_ECI[(System.Int32)value_Renamed];
        }

        /// <param name="name">character set ECI encoding name
        /// </param>
        /// <returns> {@link CharacterSetECI} representing ECI for character encoding, or null if it is legal
        /// but unsupported
        /// </returns>
        internal static CharacterSetECI getCharacterSetECIByName(System.String name)
        {
            if (NAME_TO_ECI == null)
            {
                initialize();
            }
            return (CharacterSetECI)NAME_TO_ECI[name];
        }
    }
    #endregion
    #region ErrorCorrectionLevelInternal
    /// <summary>
    /// <p>See ISO 18004:2006, 6.5.1. This enum encapsulates the four error correction levels
    /// defined by the QR code standard.</p>
    /// </summary>
    internal sealed class ErrorCorrectionLevelInternal
    {
        internal int Bits
        {
            get
            {
                return bits;
            }

        }
        internal System.String Name
        {
            get
            {
                return name;
            }

        }

        // No, we can't use an enum here. J2ME doesn't support it.

        /// <summary> L = ~7% correction</summary>
        public static readonly ErrorCorrectionLevelInternal L = new ErrorCorrectionLevelInternal(0, 0x01, "L");
        /// <summary> M = ~15% correction</summary>
        public static readonly ErrorCorrectionLevelInternal M = new ErrorCorrectionLevelInternal(1, 0x00, "M");
        /// <summary> Q = ~25% correction</summary>
        public static readonly ErrorCorrectionLevelInternal Q = new ErrorCorrectionLevelInternal(2, 0x03, "Q");
        /// <summary> H = ~30% correction</summary>
        public static readonly ErrorCorrectionLevelInternal H = new ErrorCorrectionLevelInternal(3, 0x02, "H");
        private static readonly ErrorCorrectionLevelInternal[] FOR_BITS = new ErrorCorrectionLevelInternal[] { M, L, H, Q };
        private int ordinal_Renamed_Field;
        private int bits;
        private System.String name;
        private ErrorCorrectionLevelInternal(int ordinal, int bits, System.String name)
        {
            this.ordinal_Renamed_Field = ordinal;
            this.bits = bits;
            this.name = name;
        }

        internal int ordinal()
        {
            return ordinal_Renamed_Field;
        }

        public override System.String ToString()
        {
            return name;
        }

        /// <param name="bits">int containing the two bits encoding a QR Code's error correction level
        /// </param>
        /// <returns> {@link ErrorCorrectionLevelInternal} representing the encoded error correction level
        /// </returns>
        internal static ErrorCorrectionLevelInternal forBits(int bits)
        {
            if (bits < 0 || bits >= FOR_BITS.Length)
            {
                throw new System.ArgumentException();
            }
            return FOR_BITS[bits];
        }
    }
	#endregion
    #region FormatInformation
    /// <summary>
    /// Encapsulates a QR Code's format information, including the data mask used and
    /// error correction level.
    /// </summary>
    /// <seealso cref="DataMask"></seealso>
    /// <seealso cref="ErrorCorrectionLevelInternal"></seealso>
    sealed class FormatInformation
    {
        internal ErrorCorrectionLevelInternal ErrorCorrectionLevelInternal
        {
            get
            {
                return m_ErrorCorrectionLevelInternal;
            }

        }
        internal sbyte DataMask
        {
            get
            {
                return dataMask;
            }

        }

        private const int FORMAT_INFO_MASK_QR = 0x5412;

        /// <summary> See ISO 18004:2006, Annex C, Table C.1</summary>
        private static readonly int[][] FORMAT_INFO_DECODE_LOOKUP = new int[][] { new int[] { 0x5412, 0x00 }, new int[] { 0x5125, 0x01 }, new int[] { 0x5E7C, 0x02 }, new int[] { 0x5B4B, 0x03 }, new int[] { 0x45F9, 0x04 }, new int[] { 0x40CE, 0x05 }, new int[] { 0x4F97, 0x06 }, new int[] { 0x4AA0, 0x07 }, new int[] { 0x77C4, 0x08 }, new int[] { 0x72F3, 0x09 }, new int[] { 0x7DAA, 0x0A }, new int[] { 0x789D, 0x0B }, new int[] { 0x662F, 0x0C }, new int[] { 0x6318, 0x0D }, new int[] { 0x6C41, 0x0E }, new int[] { 0x6976, 0x0F }, new int[] { 0x1689, 0x10 }, new int[] { 0x13BE, 0x11 }, new int[] { 0x1CE7, 0x12 }, new int[] { 0x19D0, 0x13 }, new int[] { 0x0762, 0x14 }, new int[] { 0x0255, 0x15 }, new int[] { 0x0D0C, 0x16 }, new int[] { 0x083B, 0x17 }, new int[] { 0x355F, 0x18 }, new int[] { 0x3068, 0x19 }, new int[] { 0x3F31, 0x1A }, new int[] { 0x3A06, 0x1B }, new int[] { 0x24B4, 0x1C }, new int[] { 0x2183, 0x1D }, new int[] { 0x2EDA, 0x1E }, new int[] { 0x2BED, 0x1F } };
        /// <summary> Offset i holds the number of 1 bits in the binary representation of i</summary>
        private static readonly int[] BITS_SET_IN_HALF_BYTE = new int[] { 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4 };
        private ErrorCorrectionLevelInternal m_ErrorCorrectionLevelInternal;
        private sbyte dataMask;
        private FormatInformation(int formatInfo)
        {
            // Bits 3,4
            m_ErrorCorrectionLevelInternal = ErrorCorrectionLevelInternal.forBits((formatInfo >> 3) & 0x03);
            // Bottom 3 bits
            dataMask = (sbyte)(formatInfo & 0x07);
        }

        internal static int numBitsDiffering(int a, int b)
        {
            a ^= b; // a now has a 1 bit exactly where its bit differs with b's
            // Count bits set quickly with a series of lookups:
            return BITS_SET_IN_HALF_BYTE[a & 0x0F] + BITS_SET_IN_HALF_BYTE[(SupportClass.URShift(a, 4) & 0x0F)] + BITS_SET_IN_HALF_BYTE[(SupportClass.URShift(a, 8) & 0x0F)] + BITS_SET_IN_HALF_BYTE[(SupportClass.URShift(a, 12) & 0x0F)] + BITS_SET_IN_HALF_BYTE[(SupportClass.URShift(a, 16) & 0x0F)] + BITS_SET_IN_HALF_BYTE[(SupportClass.URShift(a, 20) & 0x0F)] + BITS_SET_IN_HALF_BYTE[(SupportClass.URShift(a, 24) & 0x0F)] + BITS_SET_IN_HALF_BYTE[(SupportClass.URShift(a, 28) & 0x0F)];
        }

        /// <param name="maskedFormatInfo">format info indicator, with mask still applied
        /// </param>
        /// <returns> information about the format it specifies, or <code>null</code>
        /// if doesn't seem to match any known pattern
        /// </returns>
        internal static FormatInformation decodeFormatInformation(int maskedFormatInfo)
        {
            FormatInformation formatInfo = doDecodeFormatInformation(maskedFormatInfo);
            if (formatInfo != null)
            {
                return formatInfo;
            }
            // Should return null, but, some QR codes apparently
            // do not mask this info. Try again by actually masking the pattern
            // first
            return doDecodeFormatInformation(maskedFormatInfo ^ FORMAT_INFO_MASK_QR);
        }

        private static FormatInformation doDecodeFormatInformation(int maskedFormatInfo)
        {
            // Find the int in FORMAT_INFO_DECODE_LOOKUP with fewest bits differing
            int bestDifference = System.Int32.MaxValue;
            int bestFormatInfo = 0;
            for (int i = 0; i < FORMAT_INFO_DECODE_LOOKUP.Length; i++)
            {
                int[] decodeInfo = FORMAT_INFO_DECODE_LOOKUP[i];
                int targetInfo = decodeInfo[0];
                if (targetInfo == maskedFormatInfo)
                {
                    // Found an exact match
                    return new FormatInformation(decodeInfo[1]);
                }
                int bitsDifference = numBitsDiffering(maskedFormatInfo, targetInfo);
                if (bitsDifference < bestDifference)
                {
                    bestFormatInfo = decodeInfo[1];
                    bestDifference = bitsDifference;
                }
            }
            // Hamming distance of the 32 masked codes is 7, by construction, so <= 3 bits
            // differing means we found a match
            if (bestDifference <= 3)
            {
                return new FormatInformation(bestFormatInfo);
            }
            return null;
        }

        public override int GetHashCode()
        {
            return (m_ErrorCorrectionLevelInternal.ordinal() << 3) | (int)dataMask;
        }

        public override bool Equals(System.Object o)
        {
            if (!(o is FormatInformation))
            {
                return false;
            }
            FormatInformation other = (FormatInformation)o;
            return this.m_ErrorCorrectionLevelInternal == other.m_ErrorCorrectionLevelInternal && this.dataMask == other.dataMask;
        }
    }
    #endregion
    #region Mode
    /// <summary>
    /// See ISO 18004:2006, 6.4.1, Tables 2 and 3. This enum encapsulates the various modes in which
	/// data can be encoded to bits in the QR code standard.
	/// </summary>
	internal sealed class Mode
	{
		internal int Bits
		{
			get
			{
				return bits;
			}
			
		}
		internal System.String Name
		{
			get
			{
				return name;
			}
			
		}
		
		// No, we can't use an enum here. J2ME doesn't support it.
		
		//UPGRADE_NOTE: Final was removed from the declaration of 'TERMINATOR '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'"
		internal static readonly Mode TERMINATOR = new Mode(new int[]{0, 0, 0}, 0x00, "TERMINATOR"); // Not really a mode...
		//UPGRADE_NOTE: Final was removed from the declaration of 'NUMERIC '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'"
		internal static readonly Mode NUMERIC = new Mode(new int[]{10, 12, 14}, 0x01, "NUMERIC");
		//UPGRADE_NOTE: Final was removed from the declaration of 'ALPHANUMERIC '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'"
		internal static readonly Mode ALPHANUMERIC = new Mode(new int[]{9, 11, 13}, 0x02, "ALPHANUMERIC");
		//UPGRADE_NOTE: Final was removed from the declaration of 'STRUCTURED_APPEND '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'"
		internal static readonly Mode STRUCTURED_APPEND = new Mode(new int[]{0, 0, 0}, 0x03, "STRUCTURED_APPEND"); // Not supported
		//UPGRADE_NOTE: Final was removed from the declaration of 'BYTE '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'"
		internal static readonly Mode BYTE = new Mode(new int[]{8, 16, 16}, 0x04, "BYTE");
		//UPGRADE_NOTE: Final was removed from the declaration of 'ECI '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'"
		internal static readonly Mode ECI = new Mode(null, 0x07, "ECI"); // character counts don't apply
		//UPGRADE_NOTE: Final was removed from the declaration of 'KANJI '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'"
		internal static readonly Mode KANJI = new Mode(new int[]{8, 10, 12}, 0x08, "KANJI");
		//UPGRADE_NOTE: Final was removed from the declaration of 'FNC1_FIRST_POSITION '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'"
		internal static readonly Mode FNC1_FIRST_POSITION = new Mode(null, 0x05, "FNC1_FIRST_POSITION");
		//UPGRADE_NOTE: Final was removed from the declaration of 'FNC1_SECOND_POSITION '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'"
		internal static readonly Mode FNC1_SECOND_POSITION = new Mode(null, 0x09, "FNC1_SECOND_POSITION");
		
		//UPGRADE_NOTE: Final was removed from the declaration of 'characterCountBitsForVersions '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'"
		private int[] characterCountBitsForVersions;
		//UPGRADE_NOTE: Final was removed from the declaration of 'bits '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'"
		private int bits;
		//UPGRADE_NOTE: Final was removed from the declaration of 'name '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'"
		private System.String name;
		
		private Mode(int[] characterCountBitsForVersions, int bits, System.String name)
		{
			this.characterCountBitsForVersions = characterCountBitsForVersions;
			this.bits = bits;
			this.name = name;
		}
		
		/// <param name="bits">four bits encoding a QR Code data mode
		/// </param>
		/// <returns> {@link Mode} encoded by these bits
		/// </returns>
		/// <throws>  IllegalArgumentException if bits do not correspond to a known mode </throws>
		internal static Mode forBits(int bits)
		{
			switch (bits)
			{
				
				case 0x0: 
					return TERMINATOR;
				
				case 0x1: 
					return NUMERIC;
				
				case 0x2: 
					return ALPHANUMERIC;
				
				case 0x3: 
					return STRUCTURED_APPEND;
				
				case 0x4: 
					return BYTE;
				
				case 0x5: 
					return FNC1_FIRST_POSITION;
				
				case 0x7: 
					return ECI;
				
				case 0x8: 
					return KANJI;
				
				case 0x9: 
					return FNC1_SECOND_POSITION;
				
				default: 
					throw new System.ArgumentException();
				
			}
		}
		
		/// <param name="version">version in question
		/// </param>
		/// <returns> number of bits used, in this QR Code symbol {@link Version}, to encode the
		/// count of characters that will follow encoded in this {@link Mode}
		/// </returns>
		internal int getCharacterCountBits(Version version)
		{
			if (characterCountBitsForVersions == null)
			{
				throw new System.ArgumentException("Character count doesn't apply to this mode");
			}
			int number = version.VersionNumber;
			int offset;
			if (number <= 9)
			{
				offset = 0;
			}
			else if (number <= 26)
			{
				offset = 1;
			}
			else
			{
				offset = 2;
			}
			return characterCountBitsForVersions[offset];
		}
		
		public override System.String ToString()
		{
			return name;
		}
	}
    #endregion
    #region QRCodeInternal
    internal sealed class QRCodeInternal
    {
        internal Mode Mode
        {
            // Mode of the QR Code.

            get
            {
                return mode;
            }

            set
            {
                mode = value;
            }

        }
        internal ErrorCorrectionLevelInternal EcLevelInternal
        {
            // Error correction level of the QR Code.

            get
            {
                return m_EcLevelInternal;
            }

            set
            {
                m_EcLevelInternal = value;
            }

        }
        internal int Version
        {
            // Version of the QR Code.  The bigger size, the bigger version.

            get
            {
                return version;
            }

            set
            {
                version = value;
            }

        }
        public int MatrixWidth
        {
            // ByteMatrix width of the QR Code.

            get
            {
                return matrixWidth;
            }

            set
            {
                matrixWidth = value;
            }

        }
        internal int MaskPattern
        {
            // Mask pattern of the QR Code.

            get
            {
                return maskPattern;
            }

            set
            {
                maskPattern = value;
            }

        }
        internal int NumTotalBytes
        {
            // Number of total bytes in the QR Code.

            get
            {
                return numTotalBytes;
            }

            set
            {
                numTotalBytes = value;
            }

        }
        internal int NumDataBytes
        {
            // Number of data bytes in the QR Code.

            get
            {
                return numDataBytes;
            }

            set
            {
                numDataBytes = value;
            }

        }
        internal int NumECBytes
        {
            // Number of error correction bytes in the QR Code.

            get
            {
                return numECBytes;
            }

            set
            {
                numECBytes = value;
            }

        }
        internal int NumRSBlocks
        {
            // Number of Reedsolomon blocks in the QR Code.

            get
            {
                return numRSBlocks;
            }

            set
            {
                numRSBlocks = value;
            }

        }
        public ByteMatrix Matrix
        {
            // ByteMatrix data of the QR Code.

            get
            {
                return matrix;
            }

            // This takes ownership of the 2D array.

            set
            {
                matrix = value;
            }

        }
        internal bool Valid
        {
            // Checks all the member variables are set properly. Returns true on success. Otherwise, returns
            // false.

            get
            {
                return mode != null && m_EcLevelInternal != null && version != -1 && matrixWidth != -1 && maskPattern != -1 && numTotalBytes != -1 && numDataBytes != -1 && numECBytes != -1 && numRSBlocks != -1 && isValidMaskPattern(maskPattern) && numTotalBytes == numDataBytes + numECBytes && matrix != null && matrixWidth == matrix.Width && matrix.Width == matrix.Height; // Must be square.
            }

        }

        internal const int NUM_MASK_PATTERNS = 8;

        private Mode mode;
        private ErrorCorrectionLevelInternal m_EcLevelInternal;
        private int version;
        private int matrixWidth;
        private int maskPattern;
        private int numTotalBytes;
        private int numDataBytes;
        private int numECBytes;
        private int numRSBlocks;
        private ByteMatrix matrix;

        public QRCodeInternal()
        {
            mode = null;
            m_EcLevelInternal = null;
            version = -1;
            matrixWidth = -1;
            maskPattern = -1;
            numTotalBytes = -1;
            numDataBytes = -1;
            numECBytes = -1;
            numRSBlocks = -1;
            matrix = null;
        }


        // Return the value of the module (cell) pointed by "x" and "y" in the matrix of the QR Code. They
        // call cells in the matrix "modules". 1 represents a black cell, and 0 represents a white cell.
        internal int at(int x, int y)
        {
            // The value must be zero or one.
            int value_Renamed = matrix.get_Renamed(x, y);
            if (!(value_Renamed == 0 || value_Renamed == 1))
            {
                // this is really like an assert... not sure what better exception to use?
                throw new System.SystemException("Bad value");
            }
            return value_Renamed;
        }

        // Return debug String.
        public override System.String ToString()
        {
            System.Text.StringBuilder result = new System.Text.StringBuilder(200);
            result.Append("<<\n");
            result.Append(" mode: ");
            result.Append(mode);
            result.Append("\n m_EcLevelInternal: ");
            result.Append(m_EcLevelInternal);
            result.Append("\n version: ");
            result.Append(version);
            result.Append("\n matrixWidth: ");
            result.Append(matrixWidth);
            result.Append("\n maskPattern: ");
            result.Append(maskPattern);
            result.Append("\n numTotalBytes: ");
            result.Append(numTotalBytes);
            result.Append("\n numDataBytes: ");
            result.Append(numDataBytes);
            result.Append("\n numECBytes: ");
            result.Append(numECBytes);
            result.Append("\n numRSBlocks: ");
            result.Append(numRSBlocks);
            if (matrix == null)
            {
                result.Append("\n matrix: null\n");
            }
            else
            {
                result.Append("\n matrix:\n");
                result.Append(matrix.ToString());
            }
            result.Append(">>\n");
            return result.ToString();
        }

        // Check if "mask_pattern" is valid.
        internal static bool isValidMaskPattern(int maskPattern)
        {
            return maskPattern >= 0 && maskPattern < NUM_MASK_PATTERNS;
        }
    }
    #endregion
    #region ReaderException
    /// <summary> The general exception class throw when something goes wrong during decoding of a barcode.
    /// This includes, but is not limited to, failing checksums / error correction algorithms, being
    /// unable to locate finder timing patterns, and so on.
    /// 
    /// </summary>
    /// <author>  Sean Owen
    /// </author>
    /// <author>www.Redivivus.in (suraj.supekar@redivivus.in) - Ported from ZXING Java Source 
    /// </author>

    [Serializable]
    internal sealed class ReaderException : System.Exception
    {
        internal static ReaderException Instance
        {
            get
            {
                return instance;
            }

        }

        // TODO: Currently we throw up to 400 ReaderExceptions while scanning a single 240x240 image before
        // rejecting it. This involves a lot of overhead and memory allocation, and affects both performance
        // and latency on continuous scan clients. In the future, we should change all the decoders not to
        // throw exceptions for routine events, like not finding a barcode on a given row. Instead, we
        // should return error codes back to the callers, and simply delete this class. In the mean time, I
        // have altered this class to be as lightweight as possible, by ignoring the exception string, and
        // by disabling the generation of stack traces, which is especially time consuming. These are just
        // temporary measures, pending the big cleanup.

        //UPGRADE_NOTE: Final was removed from the declaration of 'instance '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'"
        private static readonly ReaderException instance = new ReaderException();

        // EXCEPTION TRACKING SUPPORT
        // Identifies who is throwing exceptions and how often. To use:
        //
        // 1. Uncomment these lines and the code below which uses them.
        // 2. Uncomment the two corresponding lines in j2se/CommandLineRunner.decode()
        // 3. Change core to build as Java 1.5 temporarily
        //  private static int exceptionCount = 0;
        //  private static Map<String,Integer> throwers = new HashMap<String,Integer>(32);

        private ReaderException()
        {
            // do nothing
        }

        //  internal static int getExceptionCountAndReset() {
        //    int temp = exceptionCount;
        //    exceptionCount = 0;
        //    return temp;
        //  }
        //
        //  internal static String getThrowersAndReset() {
        //    StringBuilder builder = new StringBuilder(1024);
        //    Object[] keys = throwers.keySet().toArray();
        //    for (int x = 0; x < keys.length; x++) {
        //      String key = (String) keys[x];
        //      Integer value = throwers.get(key);
        //      builder.append(key);
        //      builder.append(": ");
        //      builder.append(value);
        //      builder.append("\n");
        //    }
        //    throwers.clear();
        //    return builder.toString();
        //  }

        // Prevent stack traces from being taken
        // srowen says: huh, my IDE is saying this is not an override. native methods can't be overridden?
        // This, at least, does not hurt. Because we use a singleton pattern here, it doesn't matter anyhow.
        //UPGRADE_NOTE: Exception 'java.lang.Throwable' was converted to 'System.Exception' which has different behavior. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1100'"
        //UPGRADE_NOTE: The equivalent of method 'java.lang.Throwable.fillInStackTrace' is not an override method. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1143'"
        internal System.Exception fillInStackTrace()
        {
            return null;
        }
    }
	#endregion
    #region WriterException
    /// <summary>
    /// A base class which covers the range of exceptions which may occur when encoding a barcode using
    /// the Writer framework.
    /// </summary>
    [Serializable]
    internal sealed class WriterException : System.Exception
    {

        internal WriterException()
            : base()
        {
        }

        internal WriterException(System.String message)
            : base(message)
        {
        }
    }
    #endregion
    #region Version
    /// <summary>
    /// See ISO 18004:2006 Annex D
    /// </summary>
    internal sealed class Version
    {
        internal int VersionNumber
        {
            get
            {
                return versionNumber;
            }

        }
        internal int[] AlignmentPatternCenters
        {
            get
            {
                return alignmentPatternCenters;
            }

        }
        internal int TotalCodewords
        {
            get
            {
                return totalCodewords;
            }

        }
        internal int DimensionForVersion
        {
            get
            {
                return 17 + 4 * versionNumber;
            }

        }

        /// <summary>
        /// See ISO 18004:2006 Annex D.
        /// Element i represents the raw version bits that specify version i + 7
        /// </summary>
        private static readonly int[] VERSION_DECODE_INFO = new int[] { 0x07C94, 0x085BC, 0x09A99, 0x0A4D3, 0x0BBF6, 0x0C762, 0x0D847, 0x0E60D, 0x0F928, 0x10B78, 0x1145D, 0x12A17, 0x13532, 0x149A6, 0x15683, 0x168C9, 0x177EC, 0x18EC4, 0x191E1, 0x1AFAB, 0x1B08E, 0x1CC1A, 0x1D33F, 0x1ED75, 0x1F250, 0x209D5, 0x216F0, 0x228BA, 0x2379F, 0x24B0B, 0x2542E, 0x26A64, 0x27541, 0x28C69 };
        private static readonly Version[] VERSIONS = buildVersions();
        private int versionNumber;
        private int[] alignmentPatternCenters;
        private ECBlocks[] ecBlocks;
        private int totalCodewords;
        private Version(int versionNumber, int[] alignmentPatternCenters, ECBlocks ecBlocks1, ECBlocks ecBlocks2, ECBlocks ecBlocks3, ECBlocks ecBlocks4)
        {
            this.versionNumber = versionNumber;
            this.alignmentPatternCenters = alignmentPatternCenters;
            this.ecBlocks = new ECBlocks[] { ecBlocks1, ecBlocks2, ecBlocks3, ecBlocks4 };
            int total = 0;
            int ecCodewords = ecBlocks1.ECCodewordsPerBlock;
            ECB[] ecbArray = ecBlocks1.getECBlocks();
            for (int i = 0; i < ecbArray.Length; i++)
            {
                ECB ecBlock = ecbArray[i];
                total += ecBlock.Count * (ecBlock.DataCodewords + ecCodewords);
            }
            this.totalCodewords = total;
        }

        internal ECBlocks getECBlocksForLevel(ErrorCorrectionLevelInternal m_EcLevelInternal)
        {
            return ecBlocks[m_EcLevelInternal.ordinal()];
        }

        /// <summary> <p>Deduces version information purely from QR Code dimensions.</p>
        /// 
        /// </summary>
        /// <param name="dimension">dimension in modules
        /// </param>
        /// <returns> {@link Version} for a QR Code of that dimension
        /// </returns>
        /// <throws>  ReaderException if dimension is not 1 mod 4 </throws>
        internal static Version getProvisionalVersionForDimension(int dimension)
        {
            if (dimension % 4 != 1)
            {
                throw ReaderException.Instance;
            }
            try
            {
                return getVersionForNumber((dimension - 17) >> 2);
            }
            catch (System.ArgumentException)
            {
                throw ReaderException.Instance;
            }
        }

        internal static Version getVersionForNumber(int versionNumber)
        {
            if (versionNumber < 1 || versionNumber > 40)
            {
                throw new System.ArgumentException();
            }
            return VERSIONS[versionNumber - 1];
        }

        internal static Version decodeVersionInformation(int versionBits)
        {
            int bestDifference = System.Int32.MaxValue;
            int bestVersion = 0;
            for (int i = 0; i < VERSION_DECODE_INFO.Length; i++)
            {
                int targetVersion = VERSION_DECODE_INFO[i];
                // Do the version info bits match exactly? done.
                if (targetVersion == versionBits)
                {
                    return getVersionForNumber(i + 7);
                }
                // Otherwise see if this is the closest to a real version info bit string
                // we have seen so far
                int bitsDifference = FormatInformation.numBitsDiffering(versionBits, targetVersion);
                if (bitsDifference < bestDifference)
                {
                    bestVersion = i + 7;
                    bestDifference = bitsDifference;
                }
            }
            // We can tolerate up to 3 bits of error since no two version info codewords will
            // differ in less than 4 bits.
            if (bestDifference <= 3)
            {
                return getVersionForNumber(bestVersion);
            }
            // If we didn't find a close enough match, fail
            return null;
        }

        /// <summary> See ISO 18004:2006 Annex E</summary>
        internal BitMatrixInternal buildFunctionPattern()
        {
            int dimension = DimensionForVersion;
            BitMatrixInternal bitMatrixInternal = new BitMatrixInternal(dimension);

            // Top left finder pattern + separator + format
            bitMatrixInternal.setRegion(0, 0, 9, 9);
            // Top right finder pattern + separator + format
            bitMatrixInternal.setRegion(dimension - 8, 0, 8, 9);
            // Bottom left finder pattern + separator + format
            bitMatrixInternal.setRegion(0, dimension - 8, 9, 8);

            // Alignment patterns
            int max = alignmentPatternCenters.Length;
            for (int x = 0; x < max; x++)
            {
                int i = alignmentPatternCenters[x] - 2;
                for (int y = 0; y < max; y++)
                {
                    if ((x == 0 && (y == 0 || y == max - 1)) || (x == max - 1 && y == 0))
                    {
                        // No alignment patterns near the three finder paterns
                        continue;
                    }
                    bitMatrixInternal.setRegion(alignmentPatternCenters[y] - 2, i, 5, 5);
                }
            }

            // Vertical timing pattern
            bitMatrixInternal.setRegion(6, 9, 1, dimension - 17);
            // Horizontal timing pattern
            bitMatrixInternal.setRegion(9, 6, dimension - 17, 1);

            if (versionNumber > 6)
            {
                // Version info, top right
                bitMatrixInternal.setRegion(dimension - 11, 0, 3, 6);
                // Version info, bottom left
                bitMatrixInternal.setRegion(0, dimension - 11, 6, 3);
            }

            return bitMatrixInternal;
        }

        /// <summary> <p>Encapsulates a set of error-correction blocks in one symbol version. Most versions will
        /// use blocks of differing sizes within one version, so, this encapsulates the parameters for
        /// each set of blocks. It also holds the number of error-correction codewords per block since it
        /// will be the same across all blocks within one version.</p>
        /// </summary>
        internal sealed class ECBlocks
        {
            internal int ECCodewordsPerBlock
            {
                get
                {
                    return ecCodewordsPerBlock;
                }

            }
            internal int NumBlocks
            {
                get
                {
                    int total = 0;
                    for (int i = 0; i < ecBlocks.Length; i++)
                    {
                        total += ecBlocks[i].Count;
                    }
                    return total;
                }

            }
            internal int TotalECCodewords
            {
                get
                {
                    return ecCodewordsPerBlock * NumBlocks;
                }

            }
            private int ecCodewordsPerBlock;
            private ECB[] ecBlocks;

            internal ECBlocks(int ecCodewordsPerBlock, ECB ecBlocks)
            {
                this.ecCodewordsPerBlock = ecCodewordsPerBlock;
                this.ecBlocks = new ECB[] { ecBlocks };
            }

            internal ECBlocks(int ecCodewordsPerBlock, ECB ecBlocks1, ECB ecBlocks2)
            {
                this.ecCodewordsPerBlock = ecCodewordsPerBlock;
                this.ecBlocks = new ECB[] { ecBlocks1, ecBlocks2 };
            }

            internal ECB[] getECBlocks()
            {
                return ecBlocks;
            }
        }

        /// <summary> <p>Encapsualtes the parameters for one error-correction block in one symbol version.
        /// This includes the number of data codewords, and the number of times a block with these
        /// parameters is used consecutively in the QR code version's format.</p>
        /// </summary>
        internal sealed class ECB
        {
            internal int Count
            {
                get
                {
                    return count;
                }

            }
            internal int DataCodewords
            {
                get
                {
                    return dataCodewords;
                }

            }
            private int count;
            private int dataCodewords;

            internal ECB(int count, int dataCodewords)
            {
                this.count = count;
                this.dataCodewords = dataCodewords;
            }
        }

        public override System.String ToString()
        {
            return System.Convert.ToString(versionNumber);
        }

        /// <summary>
        /// See ISO 18004:2006 6.5.1 Table 9
        /// </summary>
        private static Version[] buildVersions()
        {
            return new Version[]{
                new Version(1, new int[]{}, new ECBlocks(7, new ECB(1, 19)), new ECBlocks(10, new ECB(1, 16)), new ECBlocks(13, new ECB(1, 13)), new ECBlocks(17, new ECB(1, 9))), 
                new Version(2, new int[]{6, 18}, new ECBlocks(10, new ECB(1, 34)), new ECBlocks(16, new ECB(1, 28)), new ECBlocks(22, new ECB(1, 22)), new ECBlocks(28, new ECB(1, 16))), 
                new Version(3, new int[]{6, 22}, new ECBlocks(15, new ECB(1, 55)), new ECBlocks(26, new ECB(1, 44)), new ECBlocks(18, new ECB(2, 17)), new ECBlocks(22, new ECB(2, 13))), 
                new Version(4, new int[]{6, 26}, new ECBlocks(20, new ECB(1, 80)), new ECBlocks(18, new ECB(2, 32)), new ECBlocks(26, new ECB(2, 24)), new ECBlocks(16, new ECB(4, 9))), 
                new Version(5, new int[]{6, 30}, new ECBlocks(26, new ECB(1, 108)), new ECBlocks(24, new ECB(2, 43)), new ECBlocks(18, new ECB(2, 15), new ECB(2, 16)), new ECBlocks(22, new ECB(2, 11), new ECB(2, 12))), 
                new Version(6, new int[]{6, 34}, new ECBlocks(18, new ECB(2, 68)), new ECBlocks(16, new ECB(4, 27)), new ECBlocks(24, new ECB(4, 19)), new ECBlocks(28, new ECB(4, 15))), 
                new Version(7, new int[]{6, 22, 38}, new ECBlocks(20, new ECB(2, 78)), new ECBlocks(18, new ECB(4, 31)), new ECBlocks(18, new ECB(2, 14), new ECB(4, 15)), new ECBlocks(26, new ECB(4, 13), new ECB(1, 14))), 
                new Version(8, new int[]{6, 24, 42}, new ECBlocks(24, new ECB(2, 97)), new ECBlocks(22, new ECB(2, 38), new ECB(2, 39)), new ECBlocks(22, new ECB(4, 18), new ECB(2, 19)), new ECBlocks(26, new ECB(4, 14), new ECB(2, 15))), 
                new Version(9, new int[]{6, 26, 46}, new ECBlocks(30, new ECB(2, 116)), new ECBlocks(22, new ECB(3, 36), new ECB(2, 37)), new ECBlocks(20, new ECB(4, 16), new ECB(4, 17)), new ECBlocks(24, new ECB(4, 12), new ECB(4, 13))), 
                new Version(10, new int[]{6, 28, 50}, new ECBlocks(18, new ECB(2, 68), new ECB(2, 69)), new ECBlocks(26, new ECB(4, 43), new ECB(1, 44)), new ECBlocks(24, new ECB(6, 19), new ECB(2, 20)), new ECBlocks(28, new ECB(6, 15), new ECB(2, 16))),
                new Version(11, new int[]{6, 30, 54}, new ECBlocks(20, new ECB(4, 81)), new ECBlocks(30, new ECB(1, 50), new ECB(4, 51)), new ECBlocks(28, new ECB(4, 22), new ECB(4, 23)), new ECBlocks(24, new ECB(3, 12), new ECB(8, 13))), 
                new Version(12, new int[]{6, 32, 58}, new ECBlocks(24, new ECB(2, 92), new ECB(2, 93)), new ECBlocks(22, new ECB(6, 36), new ECB(2, 37)), new ECBlocks(26, new ECB(4, 20), new ECB(6, 21)), new ECBlocks(28, new ECB(7, 14), new ECB(4, 15))), 
                new Version(13, new int[]{6, 34, 62}, new ECBlocks(26, new ECB(4, 107)), new ECBlocks(22, new ECB(8, 37), new ECB(1, 38)), new ECBlocks(24, new ECB(8, 20), new ECB(4, 21)), new ECBlocks(22, new ECB(12, 11), new ECB(4, 12))), 
                new Version(14, new int[]{6, 26, 46, 66}, new ECBlocks(30, new ECB(3, 115), new ECB(1, 116)), new ECBlocks(24, new ECB(4, 40), new ECB(5, 41)), new ECBlocks(20, new ECB(11, 16), new ECB(5, 17)), new ECBlocks(24, new ECB(11, 12), new ECB(5, 13))), 
                new Version(15, new int[]{6, 26, 48, 70}, new ECBlocks(22, new ECB(5, 87), new ECB(1, 88)), new ECBlocks(24, new ECB(5, 41), new ECB(5, 42)), new ECBlocks(30, new ECB(5, 24), new ECB(7, 25)), new ECBlocks(24, new ECB(11, 12), new ECB(7, 13))), 
                new Version(16, new int[]{6, 26, 50, 74}, new ECBlocks(24, new ECB(5, 98), new ECB(1, 99)), new ECBlocks(28, new ECB(7, 45), new ECB(3, 46)), new ECBlocks(24, new ECB(15, 19), new ECB(2, 20)), new ECBlocks(30, new ECB(3, 15), new ECB(13, 16))), 
                new Version(17, new int[]{6, 30, 54, 78}, new ECBlocks(28, new ECB(1, 107), new ECB(5, 108)), new ECBlocks(28, new ECB(10, 46), new ECB(1, 47)), new ECBlocks(28, new ECB(1, 22), new ECB(15, 23)), new ECBlocks(28, new ECB(2, 14), new ECB(17, 15))), 
                new Version(18, new int[]{6, 30, 56, 82}, new ECBlocks(30, new ECB(5, 120), new ECB(1, 121)), new ECBlocks(26, new ECB(9, 43), new ECB(4, 44)), new ECBlocks(28, new ECB(17, 22), new ECB(1, 23)), new ECBlocks(28, new ECB(2, 14), new ECB(19, 15))), 
                new Version(19, new int[]{6, 30, 58, 86}, new ECBlocks(28, new ECB(3, 113), new ECB(4, 114)), new ECBlocks(26, new ECB(3, 44), new ECB(11, 45)), new ECBlocks(26, new ECB(17, 21), new ECB(4, 22)), new ECBlocks(26, new ECB(9, 13), new ECB(16, 14))), 
                new Version(20, new int[]{6, 34, 62, 90}, new ECBlocks(28, new ECB(3, 107), new ECB(5, 108)), new ECBlocks(26, new ECB(3, 41), new ECB(13, 42)), new ECBlocks(30, new ECB(15, 24), new ECB(5, 25)), new ECBlocks(28, new ECB(15, 15), new ECB(10, 16))), 
                new Version(21, new int[]{6, 28, 50, 72, 94}, new ECBlocks(28, new ECB(4, 116), new ECB(4, 117)), new ECBlocks(26, new ECB(17, 42)), new ECBlocks(28, new ECB(17, 22), new ECB(6, 23)), new ECBlocks(30, new ECB(19, 16), new ECB(6, 17))), 
                new Version(22, new int[]{6, 26, 50, 74, 98}, new ECBlocks(28, new ECB(2, 111), new ECB(7, 112)), new ECBlocks(28, new ECB(17, 46)), new ECBlocks(30, new ECB(7, 24), new ECB(16, 25)), new ECBlocks(24, new ECB(34, 13))), 
                new Version(23, new int[]{6, 30, 54, 74, 102}, new ECBlocks(30, new ECB(4, 121), new ECB(5, 122)), new ECBlocks(28, new ECB(4, 47), new ECB(14, 48)), new ECBlocks(30, new ECB(11, 24), new ECB(14, 25)), new ECBlocks(30, new ECB(16, 15), new ECB(14, 16))), 
                new Version(24, new int[]{6, 28, 54, 80, 106}, new ECBlocks(30, new ECB(6, 117), new ECB(4, 118)), new ECBlocks(28, new ECB(6, 45), new ECB(14, 46)), new ECBlocks(30, new ECB(11, 24), new ECB(16, 25)), new ECBlocks(30, new ECB(30, 16), new ECB(2, 17))), 
                new Version(25, new int[]{6, 32, 58, 84, 110}, new ECBlocks(26, new ECB(8, 106), new ECB(4, 107)), new ECBlocks(28, new ECB(8, 47), new ECB(13, 48)), new ECBlocks(30, new ECB(7, 24), new ECB(22, 25)), new ECBlocks(30, new ECB(22, 15), new ECB(13, 16))), 
                new Version(26, new int[]{6, 30, 58, 86, 114}, new ECBlocks(28, new ECB(10, 114), new ECB(2, 115)), new ECBlocks(28, new ECB(19, 46), new ECB(4, 47)), new ECBlocks(28, new ECB(28, 22), new ECB(6, 23)), new ECBlocks(30, new ECB(33, 16), new ECB(4, 17))), 
                new Version(27, new int[]{6, 34, 62, 90, 118}, new ECBlocks(30, new ECB(8, 122), new ECB(4, 123)), new ECBlocks(28, new ECB(22, 45), new ECB(3, 46)), new ECBlocks(30, new ECB(8, 23), new ECB(26, 24)), new ECBlocks(30, new ECB(12, 15), new ECB(28, 16))), 
                new Version(28, new int[]{6, 26, 50, 74, 98, 122}, new ECBlocks(30, new ECB(3, 117), new ECB(10, 118)), new ECBlocks(28, new ECB(3, 45), new ECB(23, 46)), new ECBlocks(30, new ECB(4, 24), new ECB(31, 25)), new ECBlocks(30, new ECB(11, 15), new ECB(31, 16))), 
                new Version(29, new int[]{6, 30, 54, 78, 102, 126}, new ECBlocks(30, new ECB(7, 116), new ECB(7, 117)), new ECBlocks(28, new ECB(21, 45), new ECB(7, 46)), new ECBlocks(30, new ECB(1, 23), new ECB(37, 24)), new ECBlocks(30, new ECB(19, 15), new ECB(26, 16))), 
                new Version(30, new int[]{6, 26, 52, 78, 104, 130}, new ECBlocks(30, new ECB(5, 115), new ECB(10, 116)), new ECBlocks(28, new ECB(19, 47), new ECB(10, 48)), new ECBlocks(30, new ECB(15, 24), new ECB(25, 25)), new ECBlocks(30, new ECB(23, 15), new ECB(25, 16))), 
                new Version(31, new int[]{6, 30, 56, 82, 108, 134}, new ECBlocks(30, new ECB(13, 115), new ECB(3, 116)), new ECBlocks(28, new ECB(2, 46), new ECB(29, 47)), new ECBlocks(30, new ECB(42, 24), new ECB(1, 25)), new ECBlocks(30, new ECB(23, 15), new ECB(28, 16))), 
                new Version(32, new int[]{6, 34, 60, 86, 112, 138}, new ECBlocks(30, new ECB(17, 115)), new ECBlocks(28, new ECB(10, 46), new ECB(23, 47)), new ECBlocks(30, new ECB(10, 24), new ECB(35, 25)), new ECBlocks(30, new ECB(19, 15), new ECB(35, 16))), 
                new Version(33, new int[]{6, 30, 58, 86, 114, 142}, new ECBlocks(30, new ECB(17, 115), new ECB(1, 116)), new ECBlocks(28, new ECB(14, 46), new ECB(21, 47)), new ECBlocks(30, new ECB(29, 24), new ECB(19, 25)), new ECBlocks(30, new ECB(11, 15), new ECB(46, 16))), 
                new Version(34, new int[]{6, 34, 62, 90, 118, 146}, new ECBlocks(30, new ECB(13, 115), new ECB(6, 116)), new ECBlocks(28, new ECB(14, 46), new ECB(23, 47)), new ECBlocks(30, new ECB(44, 24), new ECB(7, 25)), new ECBlocks(30, new ECB(59, 16), new ECB(1, 17))), 
                new Version(35, new int[]{6, 30, 54, 78, 102, 126, 150}, new ECBlocks(30, new ECB(12, 121), new ECB(7, 122)), new ECBlocks(28, new ECB(12, 47), new ECB(26, 48)), new ECBlocks(30, new ECB(39, 24), new ECB(14, 25)), new ECBlocks(30, new ECB(22, 15), new ECB(41, 16))), 
                new Version(36, new int[]{6, 24, 50, 76, 102, 128, 154}, new ECBlocks(30, new ECB(6, 121), new ECB(14, 122)), new ECBlocks(28, new ECB(6, 47), new ECB(34, 48)), new ECBlocks(30, new ECB(46, 24), new ECB(10, 25)), new ECBlocks(30, new ECB(2, 15), new ECB(64, 16))), 
                new Version(37, new int[]{6, 28, 54, 80, 106, 132, 158}, new ECBlocks(30, new ECB(17, 122), new ECB(4, 123)), new ECBlocks(28, new ECB(29, 46), new ECB(14, 47)), new ECBlocks(30, new ECB(49, 24), new ECB(10, 25)), new ECBlocks(30, new ECB(24, 15), new ECB(46, 16))), 
                new Version(38, new int[]{6, 32, 58, 84, 110, 136, 162}, new ECBlocks(30, new ECB(4, 122), new ECB(18, 123)), new ECBlocks(28, new ECB(13, 46), new ECB(32, 47)), new ECBlocks(30, new ECB(48, 24), new ECB(14, 25)), new ECBlocks(30, new ECB(42, 15), new ECB(32, 16))), 
                new Version(39, new int[]{6, 26, 54, 82, 110, 138, 166}, new ECBlocks(30, new ECB(20, 117), new ECB(4, 118)), new ECBlocks(28, new ECB(40, 47), new ECB(7, 48)), new ECBlocks(30, new ECB(43, 24), new ECB(22, 25)), new ECBlocks(30, new ECB(10, 15), new ECB(67, 16))), 
                new Version(40, new int[]{6, 30, 58, 86, 114, 142, 170}, new ECBlocks(30, new ECB(19, 118), new ECB(6, 119)), new ECBlocks(28, new ECB(18, 47), new ECB(31, 48)), new ECBlocks(30, new ECB(34, 24), new ECB(34, 25)), new ECBlocks(30, new ECB(20, 15), new ECB(61, 16)))
            };
        }
    }
    #endregion
}
